﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MinimizeEngine.Entities;
using MinimizeEngine.Managers;
using MinimizeEngine.Entities.Grid_System;
#endregion

namespace MinimizeEngine.Components.Render.Grid_System
{
    public class MEGridSectionRenderComponent : MEBaseComponent
    {
        
        #region Fields

        /// <summary>
        /// Quad Vertices
        /// </summary>
        private VertexPositionNormalTexture[] mVertices;
        
        /// <summary>
        /// Quad Indices
        /// </summary>
        private int[] mIndices;

        /// <summary>
        /// Quad Locations
        /// </summary>
        private Vector3 mOrigin, mUpperLeft, mLowerLeft, mUpperRight, mLowerRight, mNormal, mUp;

        /// <summary>
        /// Primitive Shapes Basic Effect
        /// </summary>
        private static BasicEffect mBasicEffect;

        /// <summary>
        /// Grid Sections Vertex Declaration
        /// </summary>
        private VertexDeclaration mVertexDeclaration;

        /// <summary>
        /// World Transform Matrix
        /// </summary>
        private Matrix mWorldTransformMatrix;

        /// <summary>
        /// Name of the Texture for this Grid Section Render Component
        /// </summary>
        private string mTextureName;

        /// <summary>
        /// Width of the GridSection
        /// </summary>
        private float mWidth;

        /// <summary>
        /// Height of the GridSection
        /// </summary>
        private float mHeight;

        #endregion

        #region Properties

        /// <summary>
        /// Basic Effect
        /// </summary>
        public BasicEffect BasicEffect
        {
            get { return mBasicEffect; }
            set { mBasicEffect = value; }
        }

        /// <summary>
        /// Grid Section Render Components World Transform Matrix
        /// </summary>
        public Matrix WorldTransformMatrix
        {
            get { return mWorldTransformMatrix; }
        }

        /// <summary>
        /// Grid Section Render Components Vertices
        /// </summary>
        public VertexPositionNormalTexture[] Vertices
        {
            get { return mVertices; }
        }

        /// <summary>
        /// Grid Section Render Components Indices
        /// </summary>
        public int[] Indices
        {
            get { return mIndices; }
        }

        private void CreateBoundingBox()
        {
            Vector3 min = new Vector3(Parent.Position.X - (mWidth / 2), Parent.Position.Y - 1, Parent.Position.Z - (mHeight / 2));
            Vector3 max = new Vector3(Parent.Position.X + (mWidth / 2), Parent.Position.Y + 1, Parent.Position.Z + (mHeight / 2));

            Parent.BoundingBox = new BoundingBox(min, max);
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Construct a new Render COmponent
        /// </summary>
        /// <param name="parent">Entity this will be attached to</param>
        public MEGridSectionRenderComponent(MEGridSection parent, string textureName, Vector3 normal, Vector3 up)
            : base(parent)
        {
            //Setup Vertex Declaration
            mVertexDeclaration = new VertexDeclaration(MEEngineManager.DeviceManager.GraphicsDevice, VertexPositionNormalTexture.VertexElements);

            //Set Texture Name
            mTextureName = textureName;

            //Set Width and Height
            mWidth = parent.Width;
            mHeight = parent.Height;

            //Create the Vertices and Indices
            mVertices = new VertexPositionNormalTexture[4];
            mIndices = new int[6];

            mOrigin = Parent.Position;
            mNormal = normal;
            mUp = up;

            mUpperLeft = new Vector3(-parent.Width / 2, 0, -parent.Height / 2);
            mUpperRight = new Vector3(parent.Width / 2, 0, -parent.Height / 2);
            mLowerLeft = new Vector3(-parent.Width / 2, 0, parent.Height / 2);
            mLowerRight = new Vector3(parent.Width / 2, 0, parent.Height / 2);

            //Add itself to the Master List of Base Components in the Scene Graph Manager
            MESceneGraphManager.AddComponent(this);

            InitializeVertices();
            CreateBoundingBox();
        }

        private void InitializeVertices()
        {
            //First create the Texture Coordinates for the Quads Texture
            Vector2 txUL = new Vector2(0.0f, 0.0f);
            Vector2 txUR = new Vector2(1.0f, 0.0f);
            Vector2 txLL = new Vector2(0.0f, 1.0f);
            Vector2 txLR = new Vector2(1.0f, 1.0f);

            //For each Vertex, we need to provide a Normal.
            for (int i = 0; i < mVertices.Length; i++ )
            {
                mVertices[i].Normal = mNormal;
            }

            //Now, for each Vertex we setup the Position and its Texture Coordinate
            mVertices[0].Position = mLowerLeft;
            mVertices[0].TextureCoordinate = txLL;
            mVertices[1].Position = mUpperLeft;
            mVertices[1].TextureCoordinate = txUL;
            mVertices[2].Position = mLowerRight;
            mVertices[2].TextureCoordinate = txLR;
            mVertices[3].Position = mUpperRight;
            mVertices[3].TextureCoordinate = txUR;

            //And finally we can setup the Index Buffer.
            //We use Clockwise Winding here.
            mIndices[0] = 0;
            mIndices[1] = 1;
            mIndices[2] = 2;
            mIndices[3] = 2;
            mIndices[4] = 1;
            mIndices[5] = 3;
        }

        #endregion

        #region Update

        /// <summary>
        /// Update the Line Render Component
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            mWorldTransformMatrix = Matrix.CreateScale(Parent.Scale) * Parent.Rotation * Matrix.CreateTranslation(Parent.Position);
            CreateBoundingBox();
        }

        #endregion

        #region Draw
        
        public override void Draw()
        {
            MEEngineManager.DeviceManager.GraphicsDevice.VertexDeclaration = mVertexDeclaration;
            MEEngineManager.DeviceManager.GraphicsDevice.RenderState.DepthBufferEnable = true;
            MEEngineManager.DeviceManager.GraphicsDevice.RenderState.AlphaBlendEnable = true;
            MEEngineManager.DeviceManager.GraphicsDevice.RenderState.AlphaTestEnable = true;

            mBasicEffect.World = mWorldTransformMatrix;
            mBasicEffect.View = MECameraManager.mActiveCamera.Parent.View;
            mBasicEffect.Projection = MECameraManager.mActiveCamera.Parent.Projection;

            mBasicEffect.Begin();
            foreach (EffectPass effectPass in mBasicEffect.CurrentTechnique.Passes)
            {
                effectPass.Begin();
                MEEngineManager.DeviceManager.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, mVertices, 0, 4, mIndices, 0, 2);
                effectPass.End();
            }
            mBasicEffect.End();

            if(Parent.DrawBoundingBox)
            {
                BoundingBoxRenderer.Render(Parent.BoundingBox, MEEngineManager.DeviceManager.GraphicsDevice, MECameraManager.mActiveCamera.Parent.View, MECameraManager.mActiveCamera.Parent.Projection, Color.Magenta);
            }
        }

        #endregion
    }
}
